import os
from flask import Flask, send_from_directory, send_file
from flask.json.provider import JSONProvider
from flask_cors import CORS
from flask_socketio import SocketIO
from flask_sqlalchemy import SQLAlchemy
from flask_jwt_extended import JWTManager

# 使用orjson替代标准json库来提高性能
import orjson

# 初始化扩展
db = SQLAlchemy()
jwt = JWTManager()
socketio = SocketIO()

# 自定义JSON编码器
class CustomJSONProvider(JSONProvider):
    def dumps(self, obj, **kwargs):
        return orjson.dumps(obj).decode('utf-8')
    
    def loads(self, s, **kwargs):
        return orjson.loads(s)

def create_app(config_name=None):
    """创建Flask应用实例"""
    # 设置静态文件目录
    static_folder = os.path.join(os.path.dirname(os.path.dirname(__file__)), '..', 'frontend', 'dist')
    app = Flask(__name__, static_folder=static_folder)
    
    # 加载配置
    if config_name is None:
        config_name = os.environ.get('FLASK_CONFIG', 'default')
    
    # 从配置字典中获取配置类
    from config import config
    app.config.from_object(config[config_name])
    
    # 首先调用应用初始化函数，以确保目录等已创建
    config[config_name].init_app(app)

    # 使用高性能JSON处理器
    app.json = CustomJSONProvider(app)
    
    # 初始化扩展
    CORS(app, resources={r"/api/*": {"origins": "*"}}, supports_credentials=True)
    db.init_app(app)
    jwt.init_app(app)
    
    # 初始化SocketIO（镜像更新需要WebSocket支持）
    socketio.init_app(app, cors_allowed_origins="*")
    
    # 注册蓝图
    from .routes.system import system_bp
    from .routes.network import network_bp
    from .routes.docker import docker_bp
    from .routes.updates import updates_bp
    from .routes.experiment import experiment_bp
    from .routes.config import config_bp
    from .routes.device import device_bp
    from .routes.image_update_routes import init_image_update_routes
    from .routes.intelligent_update_routes import intelligent_updates_bp
    # from .api.v2 import register_v2_blueprints  # 暂时禁用
    
    app.register_blueprint(system_bp, url_prefix='/api/system')
    app.register_blueprint(network_bp, url_prefix='/api/network')
    app.register_blueprint(docker_bp, url_prefix='/api/docker')
    app.register_blueprint(updates_bp, url_prefix='/api/updates')
    app.register_blueprint(experiment_bp, url_prefix='/api/experiment')
    app.register_blueprint(config_bp, url_prefix='/api/config')
    app.register_blueprint(device_bp, url_prefix='/api/device')
    app.register_blueprint(intelligent_updates_bp, url_prefix='/api/intelligent-updates')
    
    # 注册V2 API蓝图
    # register_v2_blueprints(app)  # 暂时禁用
    
    # 初始化并注册镜像更新蓝图
    image_update_bp = init_image_update_routes(socketio)
    app.register_blueprint(image_update_bp)
    
    # 添加前端路由
    @app.route('/')
    def index():
        """返回前端主页"""
        try:
            return send_file(os.path.join(app.static_folder, 'index.html'))
        except:
            return {
                'name': 'MoBox Dashboard API',
                'version': '1.0.0',
                'status': 'running',
                'message': 'Frontend not available, API only',
                'services': {
                    'system': '/api/system',
                    'network': '/api/network', 
                    'docker': '/api/docker',
                    'updates': '/api/updates',
                    'experiment': '/api/experiment'
                }
            }
    
    @app.route('/health')
    def health_check():
        return {'status': 'healthy', 'timestamp': app.config.get('START_TIME', 'unknown')}
    
    # V1 API路由
    @app.route('/v1/api/experiment/resource', methods=['POST'])
    def v1_experiment_resource():
        """V1 API端点 - 直接调用实验蓝图的处理函数"""
        from .routes.experiment import get_experiment_resource_v1
        return get_experiment_resource_v1()
    
    # 为前端资源提供静态文件服务
    @app.route('/assets/<path:filename>')
    def assets(filename):
        """提供前端资源文件"""
        return send_from_directory(os.path.join(app.static_folder, 'assets'), filename)
    
    # SPA路由支持：所有非API路由都返回index.html
    @app.route('/<path:path>')
    def spa_routing(path):
        """单页面应用路由支持"""
        # 如果是API路由，返回404
        if path.startswith('api/'):
            return {'error': 'API endpoint not found'}, 404
        
        # 检查是否是静态文件
        if '.' in path:
            try:
                return send_from_directory(app.static_folder, path)
            except:
                pass
        
        # 否则返回index.html（用于前端路由）
        try:
            return send_file(os.path.join(app.static_folder, 'index.html'))
        except:
            return {'error': 'Frontend not available'}, 404
    
    # 设置服务限制
    @app.before_request
    def before_request():
        pass  # 可以添加请求限流等措施
    
    # 错误处理
    @app.errorhandler(404)
    def page_not_found(e):
        return {'error': 'Resource not found'}, 404
    
    @app.errorhandler(500)
    def internal_server_error(e):
        return {'error': 'Internal server error'}, 500
    
    # 系统初始化（最小启动模式）
    with app.app_context():
        # 先关闭可能存在的系统监控服务
        try:
            from .services.system_monitor import shutdown_system_monitor
            shutdown_system_monitor()
        except Exception as e:
            app.logger.warning(f"关闭旧的系统监控服务失败: {e}")
        
        # 创建数据库表
        db.create_all()
        
        # 初始化懒加载服务管理器
        from .services.lazy_service_manager import get_service_manager
        app.service_manager = get_service_manager()
        
        # 只初始化设备状态上报服务（仅开机上报一次）
        try:
            from .services.device_report import init_device_reporting
            init_device_reporting(app)
        except ImportError:
            app.logger.warning("设备状态上报服务初始化失败：缺少必要的依赖包")
        except Exception as e:
            app.logger.error(f"设备状态上报服务初始化失败：{str(e)}")
        
        # 不再自动启动这些服务，改为按需启动：
        # init_system_monitor(app)  # 注释掉自动启动
        app.logger.info("应用采用最小启动模式，服务将按需启动")
    
    # 注册应用终止时的清理函数
    @app.teardown_appcontext
    def shutdown_app(exception=None):
        # 这个函数在每次请求上下文结束时调用，不是应用关闭时
        # 清理操作在相应的服务模块中进行
        pass
    
    # 应用关闭时清理所有懒加载服务
    import atexit
    def cleanup_services():
        try:
            if hasattr(app, 'service_manager'):
                app.service_manager.shutdown_all()
        except Exception as e:
            app.logger.error(f"清理服务时发生错误: {str(e)}")
    
    atexit.register(cleanup_services)
    
    # 不再在启动时初始化Socket.IO，改为按需初始化
    # socketio.init_app(app, ...)  # 注释掉自动启动
        
    return app 